package com.atguigu.service.impl;

import com.alibaba.fastjson.JSON;
import com.atguigu.constant.MqConst;
import com.atguigu.executor.MyExecutor;
import com.atguigu.client.CartFeignClient;
import com.atguigu.client.ProductFeignClient;
import com.atguigu.entity.OrderDetail;
import com.atguigu.entity.OrderInfo;
import com.atguigu.enums.OrderStatus;
import com.atguigu.enums.ProcessStatus;
import com.atguigu.mapper.OrderInfoMapper;
import com.atguigu.service.OrderDetailService;
import com.atguigu.service.OrderInfoService;
import com.atguigu.util.HttpClientUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.CompletableFuture;

/**
 * <p>
 * 订单表 订单表 服务实现类
 * </p>
 *
 * @author fumeng
 * @since 2021-11-11
 */
@Service
public class OrderInfoServiceImpl extends ServiceImpl<OrderInfoMapper, OrderInfo> implements OrderInfoService {

    @Autowired
    OrderDetailService orderDetailService;
    @Autowired
    RedisTemplate redisTemplate;
    @Autowired
    ProductFeignClient productFeignClient;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    CartFeignClient cartFeignClient;

    @Value("${cancel.order.delay}")
    private Integer cancelOrderDelay;
    //保存订单信息,准备支付
    @Transactional
    @Override
    public Long saveOrderInfoAndDetail(OrderInfo orderInfo) {
        //保存订单基本信息
        orderInfo.setOrderStatus(OrderStatus.UNPAID.name());
        //a.订单交易编号
        String outTradeNo = "ATGUIGU" + System.currentTimeMillis() + "" + new Random().nextInt(1000);
        orderInfo.setOutTradeNo(outTradeNo);
        //b.订单主体信息
        orderInfo.setTradeBody("购物商品信息");
        orderInfo.setCreateTime(new Date());
        //过期时间 默认设置24小时 比如说笔记本库存非常充足的24 ，如果不充足的，那么给30分钟。
        Calendar calendar = Calendar.getInstance();
        calendar.add(Calendar.DATE,1);
        orderInfo.setExpireTime(calendar.getTime());
        // 订单的进程状态 {包含订单状态}
        orderInfo.setProcessStatus(ProcessStatus.UNPAID.name());
        //还未设置订单的总价
        orderInfo.setTotalMoney(new BigDecimal(0.01));

        baseMapper.insert(orderInfo);
        //保存订单详情信息
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            orderDetail.setOrderId(orderInfo.getId());

        }
        orderDetailService.saveBatch(orderDetailList);

        //发送一个延迟消息 取消订单
        rabbitTemplate.convertAndSend(MqConst.CANCEL_ORDER_EXCHANGE,
                MqConst.CANCEL_ORDER_ROUTE_KEY,
                orderInfo.getId(),
                //过期时间
                correlationData->{
                    //注意这里单位是毫秒
                    correlationData.getMessageProperties().setDelay(cancelOrderDelay);
                    return correlationData;
                }


        );

        // 返回订单Id
        return orderInfo.getId();


    }

    //生成一个流水号
    @Override
    public String getTradeNo(String userId) {
        // 生成的流水号
        String tradeNo = UUID.randomUUID().toString();
        // 定义key,往redis存入
        String tradeNoKey = "user:"+userId+":tradeNo";
        redisTemplate.opsForValue().set(tradeNoKey,tradeNo);
        return tradeNo;

    }

    //比较流水号
    @Override
    public boolean checkTradeNo(String tradeNo, String userId) {
        String tradeNoKey = "user:"+userId+":tradeNo";
        String redisTradeNo = (String) redisTemplate.opsForValue().get(tradeNoKey);
        // 返回比较结果
        return tradeNo.equals(redisTradeNo);

    }

    //删除redis流水号
    @Override
    public void deleteTradeNo(String userId) {
        // 定义key
        String tradeNoKey = "user:"+userId+":tradeNo";
        // 删除流水号
        redisTemplate.delete(tradeNoKey);

    }

    //验证订单库存和价格
    @Override
    public List<String> checkStockAndPrice(OrderInfo orderInfo, String userId) {
        //新建一个list用于提示用户商品库存集合
        ArrayList<String> warningInfoList = new ArrayList<>();
        //异步编排集合
        // 声明一个CompletableFuture 集合
        List<CompletableFuture> multiFutureList = new ArrayList<>();

        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        if (!CollectionUtils.isEmpty(orderDetailList)){
            //不为空，调用库存接口，查看库存是否足够
            //http://localhost:8100/hasStock?skuId=28&num=2
            for (OrderDetail orderDetail : orderDetailList) {
                Long skuId = orderDetail.getSkuId();
                String skuNum = orderDetail.getSkuNum();

                CompletableFuture<Void> checkStockFuture = CompletableFuture.runAsync(() -> {
                    String result = HttpClientUtil.doGet("http://localhost:8100/hasStock?skuId=28&num=2");
                    //0：代表库存不足，  1：代表有库存
                    if ("0".equals(result)){
                        //代表库存不足
                        warningInfoList.add(orderDetail.getSkuName() + "库存不足！");
                    }
                }, MyExecutor.getInstance());
                multiFutureList.add(checkStockFuture);

                //验证价格
                CompletableFuture<Void> checkPriceFuture = CompletableFuture.runAsync(() -> {
                    //验证价格是否为最新价格
                    BigDecimal realTimePrice = productFeignClient.getSkuPrice(skuId);
                    //判断当前购物清单价格与实时价格是否相同
                    if (orderDetail.getOrderPrice().compareTo(realTimePrice)!=0){
                        //更新缓存里面的价格信息
                        warningInfoList.add(skuNum + "价格有变动！");
                        cartFeignClient.queryFromDbToRedis(userId);
                    }
                },MyExecutor.getInstance());
                //添加价格验证
                multiFutureList.add(checkPriceFuture);



                CompletableFuture[] multiFutureArray = new CompletableFuture[multiFutureList.size()];
                // 将异步编排的多个对象进行整合
                CompletableFuture.allOf(multiFutureList.toArray(multiFutureArray)).join();

            }
        }
        return warningInfoList;
    }

    //超时取消订单
    @Override
    public void updateOrderStatus(OrderInfo orderInfo, ProcessStatus processStatus) {
        orderInfo.setOrderStatus(processStatus.getOrderStatus().name());
        orderInfo.setProcessStatus(processStatus.name());
        baseMapper.updateById(orderInfo);
    }

    //查询订单信息
    @Override
    public OrderInfo getOrderInfo(Long orderId) {
        OrderInfo orderInfo = baseMapper.selectById(orderId);
        if (orderInfo!=null){
            QueryWrapper<OrderDetail> wrapper = new QueryWrapper<OrderDetail>();
            wrapper.eq("order_id", orderId);
            List<OrderDetail> orderDetailList = orderDetailService.list(wrapper);
            orderInfo.setOrderDetailList(orderDetailList);
        }
        return orderInfo;

    }

    //支付成功，减库存
    @Override
    public void sendMsgToWarehouse(OrderInfo orderInfo) {
        //将订单的状态改为已通知仓库
        updateOrderStatus(orderInfo,ProcessStatus.NOTIFIED_WARE);
        //b.需要组织数据为json字符串传递给仓库系统
        Map<String, Object> dataMap = assembleWareHouseData(orderInfo);
        String jsonData = JSON.toJSONString(dataMap);
        //c.发送消息给仓库系统
        rabbitTemplate.convertAndSend(MqConst.DECREASE_STOCK_EXCHANGE,
                MqConst.DECREASE_STOCK_ROUTE_KEY,jsonData);

    }


    private Map<String, Object> assembleWareHouseData(OrderInfo orderInfo) {
        //构造一个map用于封装数据
        Map<String, Object> dataMap = new HashMap<>();
        dataMap.put("orderId",orderInfo.getId());
        dataMap.put("consignee",orderInfo.getConsignee());
        dataMap.put("consigneeTel",orderInfo.getConsigneeTel());
        dataMap.put("orderComment",orderInfo.getOrderComment());
        dataMap.put("orderBody",orderInfo.getTradeBody());
        dataMap.put("deliveryAddress",orderInfo.getDeliveryAddress());
        dataMap.put("paymentWay",2);
        //TODO 这里有一个非常重要的字段先不写
        dataMap.put(" ",orderInfo.getWareHouseId());

        List<Map> orderDetailMapList=new ArrayList<>();
        //商品清单
        List<OrderDetail> orderDetailList = orderInfo.getOrderDetailList();
        for (OrderDetail orderDetail : orderDetailList) {
            Map<String, Object> orderDetailMap = new HashMap<>();
            orderDetailMap.put("skuId",orderDetail.getSkuId());
            orderDetailMap.put("skuNum",orderDetail.getSkuNum());
            orderDetailMap.put("skuName",orderDetail.getSkuName());
            orderDetailMapList.add(orderDetailMap);
        }
        dataMap.put("details",orderDetailMapList);
        //把map转换为json字符串
        //String jsonData = JSON.toJSONString(dataMap);
        return dataMap;
    }


    //拆单
    @Override
    public String splitOrder(Long orderId, String wareHouseIdSkuIdMapJson) {
        //获取原始订单
        OrderInfo originalOrderInfo = getOrderInfo(orderId);
        List<Map> wareHouseIdSkuIdMapList = JSON.parseArray(wareHouseIdSkuIdMapJson,Map.class);
        List<OrderInfo> childOrderList = new ArrayList<>();
        for (Map wareHouseIdSkuIdMap : wareHouseIdSkuIdMapList) {
            String wareHouseId = (String)wareHouseIdSkuIdMap.get("wareHouseId");
            List<String> skuIdList = (List<String>) wareHouseIdSkuIdMap.get("skuIdList");

            //b.设置子订单信息
            OrderInfo childOrderInfo = new OrderInfo();
            //childOrderInfo.setConsignee(originalOrderInfo.getConsignee());
            //childOrderInfo.setConsigneeTel(originalOrderInfo.getConsigneeTel());
            BeanUtils.copyProperties(originalOrderInfo,childOrderInfo);
            //拆单之后的子单主键为自动生成
            childOrderInfo.setId(null);
            //把原始订单id设置为子单的父订单id
            childOrderInfo.setParentOrderId(orderId);
            //设置子单的仓库id
            childOrderInfo.setWareHouseId(wareHouseId);

            List<OrderDetail> originalOderDetailList = originalOrderInfo.getOrderDetailList();
            //c.设置子订单详情信息
            List<OrderDetail> childOrderDetailList = new ArrayList<>();
            BigDecimal childTotalMoney=new BigDecimal(0);
            for (OrderDetail originalOderDetail : originalOderDetailList) {
                for (String skuId : skuIdList) {
                    //如果该原始订单详情属于该订单信息
                    if (Long.parseLong(skuId)==originalOderDetail.getSkuId()){
                        //把该原始订单详情信息放入子订单详情中
                        childOrderDetailList.add(originalOderDetail);
                        //设置子订单的总金额
                        BigDecimal orderPrice = originalOderDetail.getOrderPrice();
                        String skuNum = originalOderDetail.getSkuNum();
                        childTotalMoney=childTotalMoney.add(orderPrice.multiply(new BigDecimal(skuNum)));
                    }
                }
            }

            childOrderInfo.setOrderDetailList(childOrderDetailList);
            childOrderInfo.setTotalMoney(childTotalMoney);
            //d.保存子订单信息
            saveOrderInfoAndDetail(childOrderInfo);
            //添加子订单到集合中
            childOrderList.add(childOrderInfo);



        }
        //e.修改订单状态
        updateOrderStatus(originalOrderInfo,ProcessStatus.SPLIT);
        //f.返回子订单信息给库存系统 库存系统再保存到 库存工作单表 库存工作单表明细表中
        return JSON.toJSONString(childOrderList);

    }
}
